package com.wanban.downloader.db.old

import android.content.ContentValues
import android.content.Context
import android.database.Cursor
import android.database.sqlite.SQLiteDatabase
import android.text.TextUtils
import android.util.Log
import androidx.core.database.getStringOrNull
import com.google.gson.Gson
import com.wanban.downloader.db.DatabaseUtils
import com.wanban.downloader.db.DownloadEntity
import com.wanban.downloader.model.M3U8Seg
import com.wanban.downloader.model.Status
import com.wanban.downloader.utils.CommonUtils.map2String
import com.wanban.downloader.utils.CommonUtils.string2Map
import org.json.JSONArray

class M3u8VideoDownloadDatabaseHelper(private val context: Context) {

    private val mSQLiteHelper by lazy { M3U8DownloadSQLiteHelper(context) }

    fun close(){
        try {
            mSQLiteHelper.close()
        }catch (e: java.lang.Exception) {
            e.printStackTrace()
        }
    }
    /**
     * 获取数据表中的所有任务
     * @return 数据表中的所有任务
     */
    val downloadingInfos: ArrayList<DownloadEntity>
        get() {
            val items = ArrayList<DownloadEntity>()
            val db = mSQLiteHelper.readableDatabase ?: return items
            try {
                val cursor = db.query(
                    M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO,
                    null,
                    null,
                    null,
                    null, null, null, null
                ) ?: return items
                while (cursor.moveToNext()) {
                    val item = getDataByCursor(cursor)
                    items.add(item)
                }
                cursor.close()
                return items
            } catch (e: Exception) {
                e.printStackTrace()
                Log.d(DatabaseUtils.TAG, "downloadingInfos failed, exception = " + e.message)
                return items
            }
        }

    /**
     * 获取数据表中的所有任务
     * @return 数据表中的所有任务
     */
    val allDownloadTasks: ArrayList<DownloadEntity>
        get() {
            var cursors: Cursor? = null
            val items = ArrayList<DownloadEntity>()
            val db = mSQLiteHelper.readableDatabase ?: return items
            try {
                cursors = db.query(
                    M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO, null, null, null, null, null, null
                )?:return items

                while (cursors.moveToNext()) {
                    val item = getDataByCursor(cursors)
                    items.add(item)
                }
                return items
            } catch (e: Exception) {
                e.printStackTrace()
                Log.d(DatabaseUtils.TAG, "allDownloadTasks failed, exception = " + e.message)
                return items
            } finally {
                cursors?.close()
            }
        }

    fun markDownloadUpdateEvent(item: DownloadEntity): Long {
        val db = mSQLiteHelper.writableDatabase ?: return -1L
        return if (isTaskInfoExistInTable(db, item)) {
            updateDownloadProgressInfo(db, item)
        } else {
            insertVideoDownloadInfo(db, item)
        }
    }

    private fun getContentValues(item: DownloadEntity): ContentValues {
        val values = ContentValues()
        values.put(M3U8DownloadSQLiteHelper.Columns.VIDEO_ID, item.videoId)
        values.put(M3U8DownloadSQLiteHelper.Columns.STATE, item.state)
        values.put(M3U8DownloadSQLiteHelper.Columns.EPISODE, item.episode)
        values.put(M3U8DownloadSQLiteHelper.Columns.SOURCE_ID, item.sourceId)
        values.put(M3U8DownloadSQLiteHelper.Columns.RETRY_TIME, item.retryTime)
        values.put(M3U8DownloadSQLiteHelper.Columns.WATCH_TIME, item.watchTime)
        values.put(M3U8DownloadSQLiteHelper.Columns.CONTENT_LENGTH, item.contentLength)
        values.put(M3U8DownloadSQLiteHelper.Columns.URL, item.url)
        values.put(M3U8DownloadSQLiteHelper.Columns.COVER_URL, item.coverUrl)
        values.put(M3U8DownloadSQLiteHelper.Columns.VIDEO_NAME, item.videoName)
        values.put(M3U8DownloadSQLiteHelper.Columns.EPISODE_NAME, item.episodeName)
        values.put(M3U8DownloadSQLiteHelper.Columns.FILE_PATH, item.filePath)
        values.put(M3U8DownloadSQLiteHelper.Columns.COVER_FILE_PATH, item.coverFilePath)

        if (item.m3u8 != null) {
            val m3u8Json = Gson().toJson(item.m3u8)
            values.put(M3U8DownloadSQLiteHelper.Columns.M3U8, m3u8Json)
        }
        if (item.header != null) {
            values.put(M3U8DownloadSQLiteHelper.Columns.HEADER, map2String(item.header))
        }

        values.put(M3U8DownloadSQLiteHelper.Columns.FROM_URL, item.fromUrl)
        values.put(M3U8DownloadSQLiteHelper.Columns.CATEGORY, item.category)
        return values
    }

    private fun getDataByCursor(cursor: Cursor): DownloadEntity {
        val downloadUrl = cursor.getString(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.URL))
        val videoName = cursor.getString(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.VIDEO_NAME))
        val coverUrl = cursor.getString(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.COVER_URL))
        val item = DownloadEntity()
        item.url = downloadUrl
        item.videoName = videoName
        item.coverUrl = coverUrl
        item.videoId = cursor.getLong(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.VIDEO_ID))
        val watchTime = cursor.getFloat(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.WATCH_TIME))?:0f
        item.watchTime = watchTime.toLong()
        val contentLength = cursor.getFloat(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.CONTENT_LENGTH))?:0f
        item.contentLength = contentLength.toLong()
        item.state = cursor.getInt(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.STATE))
        item.episode = cursor.getInt(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.EPISODE))
        item.sourceId = cursor.getInt(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.SOURCE_ID))
        item.retryTime = cursor.getInt(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.RETRY_TIME))
        item.episodeName = cursor.getString(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.EPISODE_NAME))
        item.filePath = cursor.getString(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.FILE_PATH))
        item.coverFilePath = cursor.getString(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.COVER_FILE_PATH))
        val headerStr = cursor.getString(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.HEADER))
        if (!TextUtils.isEmpty(headerStr)) {
            item.header = string2Map(headerStr)
        }
//        val m3u8Json = cursor.getString(cursor.getColumnIndexOrThrow(M3U8DownloadSQLiteHelper.Columns.M3U8))
//        Log.e(DatabaseUtils.TAG, "m3u8Json: $m3u8Json")
//        if (!TextUtils.isEmpty(m3u8Json)) {
//            item.m3u8 = Gson().fromJson(m3u8Json, M3U8::class.java)
//            Log.e(DatabaseUtils.TAG, "m3u8转换成功")
//        }

        val fromUrlIndex = cursor.getColumnIndex(M3U8DownloadSQLiteHelper.Columns.FROM_URL)
        if (fromUrlIndex >= 0) {
            item.fromUrl = cursor.getStringOrNull(fromUrlIndex)
        }
        val categoryIndex = cursor.getColumnIndex(M3U8DownloadSQLiteHelper.Columns.CATEGORY)
        if (categoryIndex >= 0) {
            item.category = cursor.getInt(fromUrlIndex)
        }

        return item
    }

    private fun updateDownloadProgressInfo(db: SQLiteDatabase?, item: DownloadEntity): Long {
        var index: Long = -1
        if (db == null) {
            return index
        }
        db.beginTransaction()
        return try {
            val values = getContentValues(item)
            val whereClause = M3U8DownloadSQLiteHelper.Columns.URL + " = ?"
            val whereArgs = arrayOf(item.url)
            index = db.update(M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO, values, whereClause, whereArgs).toLong()
            db.setTransactionSuccessful()
            index
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(DatabaseUtils.TAG,"updateVideoDownloadInfo failed, exception = " + e.message)
            index
        } finally {
            db.endTransaction()
        }
    }

    private fun insertVideoDownloadInfo(db: SQLiteDatabase?, item: DownloadEntity): Long {
        var index: Long = -1
        if (db == null) {
            return index
        }
        db.beginTransaction()
        return try {
            val values = getContentValues(item)
            index = db.insert(M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO, null, values)
            db.setTransactionSuccessful()
            index
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(DatabaseUtils.TAG, "insertVideoDownloadInfo failed, exception = " + e.message)
            index
        } finally {
            db.endTransaction()
        }
    }

    private fun isTaskInfoExistInTable(db: SQLiteDatabase?, item: DownloadEntity): Boolean {
        if (db == null) return false
        var cursor: Cursor? = null
        return try {
            val selection = M3U8DownloadSQLiteHelper.Columns.URL + " = ?"
            val selectionArgs = arrayOf(item.url)
            cursor = db.query(
                M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO, null,
                selection, selectionArgs, null, null, null, null
            )
            cursor != null && cursor.moveToFirst() && !TextUtils.isEmpty(cursor.getString(0))
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(DatabaseUtils.TAG,"isTaskInfoExistInTable query failed, exception = " + e.message)
            false
        } finally {
            cursor?.close()
        }
    }

    fun isAddedTask(url: String): DownloadEntity? {
        val db = mSQLiteHelper.readableDatabase ?: return null
        var cursor: Cursor? = null
        return try {
            cursor = db.query(
                M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO,
                null,
                M3U8DownloadSQLiteHelper.Columns.URL + " = ?", arrayOf(url),
                null, null, null, null
            )
            if (cursor == null) return null
            var item: DownloadEntity? = null
            if (cursor.moveToNext()) {
                item = getDataByCursor(cursor)
            }
            item
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(DatabaseUtils.TAG, "isAddedTask failed, exception = " + e.message)
            null
        } finally {
            cursor?.close()
        }
    }

    fun getDownloadTask(video: Long, episode: Int, sourceId: Int): DownloadEntity? {
        val db = mSQLiteHelper.readableDatabase ?: return null
        var cursor: Cursor? = null
        return try {
            cursor = db.query(
                M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO,
                null,
                M3U8DownloadSQLiteHelper.Columns.VIDEO_ID + " = ? AND " +
                        M3U8DownloadSQLiteHelper.Columns.EPISODE + " = ? AND " +
                        M3U8DownloadSQLiteHelper.Columns.SOURCE_ID + " = ?",
                arrayOf(video.toString(), episode.toString(), sourceId.toString()),
                null, null, null, null
            )
            if (cursor == null) return null
            var item: DownloadEntity? = null
            if (cursor.moveToNext()) {
                item = getDataByCursor(cursor)
            }
            item
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(DatabaseUtils.TAG,"getDownloadTask failed, exception = " + e.message)
            null
        } finally {
            cursor?.close()
        }
    }

    fun getDownloadTask(url: String): DownloadEntity? {
        val db = mSQLiteHelper.readableDatabase ?: return null
        var cursor: Cursor? = null
        return try {
            cursor = db.query(
                M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO,
                null,
                M3U8DownloadSQLiteHelper.Columns.URL + "=?",
                arrayOf(url),
                null, null, null, null
            )
            if (cursor == null) return null
            var item: DownloadEntity? = null
            if (cursor.moveToNext()) {
                item = getDataByCursor(cursor)
            }
            item
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(DatabaseUtils.TAG,"getDownloadTask failed, exception = " + e.message)
            null
        } finally {
            cursor?.close()
        }
    }

    fun getDownloadTaskByVideoId(videoId: Long): ArrayList<DownloadEntity>? {
        val db = mSQLiteHelper.readableDatabase ?: return null
        var cursor: Cursor? = null
        return try {
            cursor = db.query(
                M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO,
                null,
                M3U8DownloadSQLiteHelper.Columns.VIDEO_ID + " = ? AND " + M3U8DownloadSQLiteHelper.Columns.STATE + " = ?",
                arrayOf(videoId.toString(), Status.SUCCESS.toString()),
                null,
                null,
                null,
                null
            )
            if (cursor == null) return null
            val tasks = ArrayList<DownloadEntity>()
            while (cursor.moveToNext()) {
                val item = getDataByCursor(cursor)
                tasks.add(item)
            }
            tasks
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(DatabaseUtils.TAG,"getDownloadTaskByVideoId failed, exception = " + e.message)
            null
        } finally {
            cursor?.close()
        }
    }

    fun hasDownloadingTask(): Boolean {
        val db = mSQLiteHelper.readableDatabase ?: return false
        var cursor: Cursor? = null
        return try {
            var hasDownloading = false
            cursor = db.query(
                M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO,
                arrayOf(M3U8DownloadSQLiteHelper.Columns.STATE),
                M3U8DownloadSQLiteHelper.Columns.STATE + " != ? AND " + M3U8DownloadSQLiteHelper.Columns.STATE + " != ?",
                arrayOf(Status.SUCCESS.toString(), Status.DELETE.toString()),
                null,
                null,
                null,
                null
            )
            if (cursor == null) return false
            if (cursor.moveToNext()) {
                hasDownloading = true
            }
            hasDownloading
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(DatabaseUtils.TAG, "hasDownloadingTask failed, exception = " + e.message)
            false
        } finally {
            cursor?.close()
        }
    }


    val successDownloads: ArrayList<DownloadEntity>
        get() {
            var cursors: Cursor? = null
            val items = ArrayList<DownloadEntity>()
            val db = mSQLiteHelper.readableDatabase ?: return items
            try {
                db.query(
                    M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO,
                    null,
                    M3U8DownloadSQLiteHelper.Columns.STATE + " = ?",
                    arrayOf(Status.SUCCESS.toString()), null, null, null, null
                ).use { cursor ->
                    cursors = cursor
                    if (cursors == null) return items
                    while (cursors?.moveToNext() == true) {
                        val item = getDataByCursor(cursors!!)
                        items.add(item)
                    }
                }
                return items
            } catch (e: Exception) {
                e.printStackTrace()
                Log.d(DatabaseUtils.TAG, "successDownloads failed, exception = " + e.message)
                return items
            } finally {
                cursors?.close()
            }
        }

    fun getTsList(tsListJson: JSONArray?): ArrayList<M3U8Seg>? {
        if (tsListJson == null) return null
        val length = tsListJson.length()
        val tsList = ArrayList<M3U8Seg>(length)
        for (i in 0 until length) {
            val ts = M3U8Seg()
            val obj = tsListJson.optJSONObject(i) ?: continue
            ts.url = obj.optString("url")
            ts.name = obj.optString("name")
            ts.parentUrl = obj.optString("parentUrl")
            ts.method = obj.optString("method")
            ts.keyUri = obj.optString("keyUri")
            ts.keyIV = obj.optString("keyIV")
            ts.initSegmentUri = obj.optString("initSegmentUri")
            ts.segmentByteRange = obj.optString("segmentByteRange")
            ts.index = obj.optInt("index")
            ts.sequence = obj.optInt("sequence")
            ts.retryCount = obj.optInt("retryCount")
            ts.tsSize = obj.optLong("tsSize")
            ts.contentLength = obj.optLong("contentLength")
            ts.duration = obj.optDouble("duration").toFloat()
            ts.hasDiscontinuity = obj.optBoolean("hasDiscontinuity")
            ts.hasKey = obj.optBoolean("hasKey")
            ts.hasInitSegment = obj.optBoolean("hasInitSegment")
            tsList.add(ts)
        }
        return tsList
    }

    fun deleteAllDownloadInfos() {
        val db = mSQLiteHelper.writableDatabase ?: return
        db.beginTransaction()
        try {
            db.delete(M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO, null, null)
            db.setTransactionSuccessful()
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(DatabaseUtils.TAG, "deleteAllDownloadInfos failed, exception = " + e.message)
        } finally {
            db.endTransaction()
        }
    }

    fun deleteDownloadItemByUrl(url: String): Int {
        var index = -1
        val db = mSQLiteHelper.writableDatabase ?: return index
        db.beginTransaction()
        return try {
            val whereClause = M3U8DownloadSQLiteHelper.Columns.URL + " = ? "
            val whereArgs = arrayOf(url)
            index = db.delete(M3U8DownloadSQLiteHelper.TABLE_VIDEO_DOWNLOAD_INFO, whereClause, whereArgs)
            db.setTransactionSuccessful()
            index
        } catch (e: Exception) {
            e.printStackTrace()
            Log.d(DatabaseUtils.TAG,"deleteDownloadItemByUrl failed, exception = " + e.message)
            index
        } finally {
            db.endTransaction()
        }
    }
}